package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.core.pojo.response.SuccessResponseData;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTaskTypeConstant;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTypeCodeConstant;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.ChannelExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.enums.SystemParamExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizChannelTypeMapper;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizDeviceMapper;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizGatewayChannelMapper;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizFosInfoParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizGatewayChannelParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizThreholdItemParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizGatewayChannelResult;
import cn.stylefeng.guns.modular.gridsystem.service.*;
import cn.stylefeng.guns.modular.gridsystem.utils.OptionalBean;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 网关通道表 服务实现类
 *
 * @author ssy
 * @date 2021/09/14 11:47
 */
@Service
@Slf4j
public class BizGatewayChannelServiceImpl extends ServiceImpl<BizGatewayChannelMapper, BizGatewayChannel> implements BizGatewayChannelService {

    @Resource
    private BizThreholdItemService bizThreholdItemService;
    @Resource
    private BizChannelTypeMapper channelTypeMapper;
    @Resource
    private BizDeviceMapper deviceMapper;
    @Resource
    private BizChannelTypeService bizChannelTypeService;
    @Resource
    private BizFosInfoService bizFosInfoService;
    @Resource
    private GatewayTaskService taskService;


    /**
     * 分页查询网关通道表
     *
     * @param bizGatewayChannelParam 网关id
     * @return PageResult<BizGatewayChannel>
     */
    @Override
    public PageResult<BizGatewayChannel> page(BizGatewayChannelParam bizGatewayChannelParam) {
        LambdaQueryWrapper<BizGatewayChannel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ObjectUtil.isNotEmpty(bizGatewayChannelParam.getGatewayId()), BizGatewayChannel::getGatewayId, bizGatewayChannelParam.getGatewayId());
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    /**
     * 查询所有biz_gateway_channel
     *
     * @param bizGatewayChannelParam
     * @return
     */
    @Override
    public List<BizGatewayChannelResult> list(BizGatewayChannelParam bizGatewayChannelParam) {
        // 构造条件
        LambdaQueryWrapper<BizGatewayChannel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ObjectUtil.isNotEmpty(bizGatewayChannelParam.getGatewayId()), BizGatewayChannel::getGatewayId, bizGatewayChannelParam.getGatewayId());
        queryWrapper.eq(ObjectUtil.isNotEmpty(bizGatewayChannelParam.getDeviceId()), BizGatewayChannel::getDeviceId, bizGatewayChannelParam.getDeviceId());
        List<BizGatewayChannelResult> channels = this.list(queryWrapper).stream()
                .map(item -> BeanUtil.toBean(item, BizGatewayChannelResult.class))
                .collect(Collectors.toList());
        List<Integer> channelTypeIds = channels.stream().map(BizGatewayChannelResult::getChannelType).collect(Collectors.toList());
        if (!channelTypeIds.isEmpty()) {
            List<BizChannelType> channelTypeList = channelTypeMapper.selectList(new LambdaUpdateWrapper<BizChannelType>()
                    .in(ObjectUtil.isNotEmpty(channelTypeIds), BizChannelType::getId, channelTypeIds));
            for (BizGatewayChannelResult channel : channels) {
                List<BizChannelType> channelTypes = channelTypeList.stream().filter(item -> item.getId().equals(channel.getChannelType())).collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(channelTypes)) {
                    channel.setChannelTypeCode(channelTypes.get(0).getCode());
                }
            }
        }
        List<BizGatewayChannelResult> collect = channels.stream().map(item -> {
            if (ObjectUtil.isEmpty(item.getDeviceId())) {
                item.setDeviceId(0);
            }
            return item;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 查询所有biz_gateway_channel不分页
     *
     * @param param
     * @return
     */
    @Override
    public List<BizGatewayChannelResult> listChannel(BizGatewayChannelParam param) {
        return this.list(new LambdaQueryWrapper<BizGatewayChannel>()
                        .eq(ObjectUtil.isNotEmpty(param.getGatewayId()), BizGatewayChannel::getGatewayId, param.getGatewayId()))
                .stream()
                .map(item -> BeanUtil.toBean(item, BizGatewayChannelResult.class))
                .collect(Collectors.toList());
    }

    /**
     * 添加biz_gateway_channel
     *
     * @param bizGatewayChannelParam
     */
    @Override
    public void add(BizGatewayChannelParam bizGatewayChannelParam) {
        // 将dto转为实体
        BizGatewayChannel bizGatewayChannel = new BizGatewayChannel();
        BeanUtil.copyProperties(bizGatewayChannelParam, bizGatewayChannel);
        final boolean save = this.save(bizGatewayChannel);
        if (save) {
            bizGatewayChannelParam.setId(bizGatewayChannel.getId());
        }
    }

    /**
     * 删除biz_gateway_channel
     *
     * @param bizGatewayChannelParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizGatewayChannelParam bizGatewayChannelParam) {
        //删除通道对应的阈值
        final LambdaQueryWrapper<BizThreholdItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizThreholdItem::getGatewayChannel, bizGatewayChannelParam.getChannel());
        queryWrapper.eq(BizThreholdItem::getGatewayId, bizGatewayChannelParam.getGatewayId());
        bizThreholdItemService.remove(queryWrapper);
        this.removeById(bizGatewayChannelParam.getId());
    }

    /**
     * 编辑biz_gateway_channel
     *
     * @param bizGatewayChannelParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean edit(BizGatewayChannelParam bizGatewayChannelParam) {
        // 根据id查询实体
        BizGatewayChannel bizGatewayChannel = this.queryBizGatewayChannel(bizGatewayChannelParam);
        Integer id = bizGatewayChannel.getId();
        BizGatewayChannel gatewayChannel = this.getById(id);
        Integer gatewayId = gatewayChannel.getGatewayId();
        BizThreholdItemParam bizThreholdItemParam = new BizThreholdItemParam();
        bizThreholdItemParam.setGatewayId(gatewayId);
        bizThreholdItemParam.setGatewayChannel(bizGatewayChannel.getChannel());
        BizThreholdItem bizThreholdItem = bizThreholdItemService.threholdItemByChannelAndGatewayId(bizThreholdItemParam);
        if (bizThreholdItem != null) {
            UpdateWrapper<BizThreholdItem> wrapper = new UpdateWrapper<>();
            wrapper.set("gateway_channel", bizGatewayChannelParam.getChannel());
            wrapper.eq("id", bizThreholdItem.getId());
            bizThreholdItemService.update(wrapper);
        }
        // 请求参数转化为实体
        BeanUtil.copyProperties(bizGatewayChannelParam, bizGatewayChannel);
        bizGatewayChannelParam.setId(id);
        boolean update = this.updateById(bizGatewayChannel);
        if (update) {
            final BizChannelType channelType = bizChannelTypeService.getById(bizGatewayChannelParam.getChannelType());
            if (channelType.getCode().equals(GatewayTypeCodeConstant.FIBRE_OPTICAL_SENSORS_CODE)) {
                LambdaQueryWrapper<BizFosInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(BizFosInfo::getChannelId, bizGatewayChannelParam.getId());
                BizFosInfo fosInfo = bizFosInfoService.getOne(queryWrapper);
                BizFosInfo bizFosInfo = new BizFosInfo();
                if (ObjectUtil.isNotNull(fosInfo)) {
                    bizFosInfo.setId(fosInfo.getId());
                }
                bizFosInfo.setChannelId(bizGatewayChannelParam.getId());
                bizFosInfo.setStartPoint(bizGatewayChannelParam.getStartPoint());
                bizFosInfo.setEndPoint(bizGatewayChannelParam.getEndPoint());
                boolean saveOrUpdate = bizFosInfoService.saveOrUpdate(bizFosInfo);
                //下发更新侦听点任务
                if (saveOrUpdate) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("opticalListeningLocation", bizGatewayChannelParam.getStartPoint());
                    map.put("channel", bizGatewayChannelParam.getChannel());
                    taskService.add(GatewayTaskTypeConstant.SYNC_OPTICAL_LISTENING_LOCATION, bizGatewayChannelParam.getGatewayId(), JSONUtil.toJsonStr(map));
                }
            }
        }
        return update;
    }

    /**
     * 查看详情biz_gateway_channel
     *
     * @param bizGatewayChannelParam
     * @return
     */
    @Override
    public BizGatewayChannel detail(BizGatewayChannelParam bizGatewayChannelParam) {
        return this.queryBizGatewayChannel(bizGatewayChannelParam);
    }

    /**
     * 通过网关id列表
     *
     * @return {@link BizGatewayChannel}
     */
    @Override
    public BizGatewayChannel listByGatewayId(Integer gatewayId, String micRouter) {
        LambdaQueryWrapper<BizGatewayChannel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizGatewayChannel::getGatewayId, gatewayId);
        queryWrapper.eq(BizGatewayChannel::getChannel, micRouter);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * 查询通道列表
     *
     * @param bizGatewayChannelParam
     * @return
     */
    @Override
    public List<BizGatewayChannelResult> listByGId(BizGatewayChannelParam bizGatewayChannelParam) {
        return this.baseMapper.listByGId(bizGatewayChannelParam);
    }

    /**
     * 分页查询biz_gateway_channel
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<BizGatewayChannelResult> pageList(BizGatewayChannelParam param) {
        return new PageResult<>(this.baseMapper.pageList(PageFactory.defaultPage(), param));
    }

    /**
     * 通过id和通道获取总数
     *
     * @param bizGatewayChannelParam
     * @return
     */
    @Override
    public Integer countByDIdAndChannel(BizGatewayChannelParam bizGatewayChannelParam) {
        Integer count = this.baseMapper.countByDIdAndChannel(bizGatewayChannelParam);
        if (count == 0) {
            bizGatewayChannelParam.setCreatedAt(DateUtil.date());
            this.add(bizGatewayChannelParam);
            final BizChannelType channelType = bizChannelTypeService.getById(bizGatewayChannelParam.getChannelType());
            if (channelType.getCode().equals(GatewayTypeCodeConstant.FIBRE_OPTICAL_SENSORS_CODE)) {
                BizFosInfoParam bizFosInfoParam = new BizFosInfoParam();
                bizFosInfoParam.setChannelId(bizGatewayChannelParam.getId());
                if (!NumberUtil.isNumber(bizGatewayChannelParam.getStartPoint()) || !NumberUtil.isNumber(bizGatewayChannelParam.getEndPoint())) {
                    throw new ServiceException("开始点位为非数字类型或结束点位为非数字类型");
                }
                if (ObjectUtil.compare(bizGatewayChannelParam.getStartPoint(), "200") < 0) {
                    throw new ServiceException("侦听点位必须大于等于200");
                }
                bizFosInfoParam.setStartPoint(bizGatewayChannelParam.getStartPoint());

                BizGatewayChannelParam channelParam = new BizGatewayChannelParam();
                channelParam.setGatewayId(bizGatewayChannelParam.getGatewayId());
                List<BizGatewayChannelResult> channelResultList = this.listChannel(channelParam);
                Optional<BizGatewayChannelResult> bizGatewayChannelResult = channelResultList.stream().filter(channelResult -> {
                            int startPointCount = bizFosInfoService.count(new LambdaQueryWrapper<BizFosInfo>().le(BizFosInfo::getStartPoint, bizGatewayChannelParam.getStartPoint()));
                            return startPointCount > 0;
                        }
                ).findFirst();

                if (!bizGatewayChannelResult.isPresent()) {
                    bizFosInfoService.add(bizFosInfoParam);
                } else {
                    throw new ServiceException("该已存在通道在改点位范围内");
                }
            }
        } else {
            throw new ServiceException("该通道已存在");
        }
        return count;
    }

    /**
     * 修改网关信息
     *
     * @param param
     */
    @Override
    public void editById(BizGatewayChannelParam param) {
        // 根据id查询实体
        BizGatewayChannel bizGatewayChannel = this.queryBizGatewayChannel(param);
        // 请求参数转化为实体
        BeanUtil.copyProperties(param, bizGatewayChannel);
        this.updateById(bizGatewayChannel);
    }

    /**
     * 通道解除绑定
     *
     * @param param 查询参数
     */
    @Override
    public void unbinding(BizGatewayChannelParam param) {
        BizGatewayChannel channel = getById(param.getId());
        if (ObjectUtil.isEmpty(channel)) {
            log.warn("通道不存在，通道主键为：{}", param.getId());
            throw new ServiceException(ChannelExceptionEnum.NOT_EXIST);
        }
        // 通道解绑
        update(new LambdaUpdateWrapper<BizGatewayChannel>()
                .eq(BizGatewayChannel::getId, channel.getId())
                .set(BizGatewayChannel::getDeviceId, null)
                .set(BizGatewayChannel::getPositionType, null)
                .set(BizGatewayChannel::getXposion, 0)
                .set(BizGatewayChannel::getYposion, 0));
    }

    /**
     * 通道标记
     *
     * @param param 查询参数
     */
    @Override
    public void mark(BizGatewayChannelParam param) {
        BizGatewayChannel channel = getById(param.getId());
        if (ObjectUtil.isEmpty(channel)) {
            log.warn("通道不存在，通道主键为：{}", param.getId());
            throw new ServiceException(ChannelExceptionEnum.NOT_EXIST);
        }
        channel.setGatewayId(param.getGatewayId());
        channel.setDeviceId(param.getDeviceId());
        channel.setXposion(param.getXposion());
        channel.setYposion(param.getYposion());
        channel.setPositionType(param.getPositionType());
        updateById(channel);
    }

    /**
     * 查询通道绑定信息
     *
     * @param param 查询参数
     * @return String
     */
    @Override
    public String queryChannelBindingInfo(BizGatewayChannelParam param) {
        OptionalBean.ofNullable(param.getId()).orElseThrow(() -> new ServiceException(SystemParamExceptionEnum.PARAM_NULL_ERROR));
        BizGatewayChannel channel = getById(param.getId());
        // 判断通道是否存在
        OptionalBean.ofNullable(channel).orElseThrow(() -> new ServiceException(ChannelExceptionEnum.NOT_EXIST));
        //判断通道是否绑定其它设备
        OptionalBean.of(channel.getDeviceId()).orElseThrow(() -> new ServiceException(ChannelExceptionEnum.NOT_BINDING_DEVICE));
        BizDevice device = deviceMapper.selectById(channel.getDeviceId());
        // 判断设备是否存在
        OptionalBean.ofNullable(device).orElseThrow(() -> new ServiceException(ChannelExceptionEnum.DEVICE_NOT_EXIST));
        return StrFormatter.format("此通道已绑定在设备{}上，确定解绑吗？", device.getDeviceName());
    }

    /**
     * 获取网关通道表
     *
     * @author ssy
     * @since 2021/09/14 11:47
     */
    private BizGatewayChannel queryBizGatewayChannel(BizGatewayChannelParam bizGatewayChannelParam) {
        return getById(bizGatewayChannelParam.getId());
    }

    /**
     * 根据网关id和通道获取网关通道
     *
     * @param gatewayId 网关id
     * @param channel   通道
     * @return BizGatewayChannel 网关通道
     */
    @Override
    public BizGatewayChannel getBizGatewayChannel(Integer gatewayId, String channel) {
        OptionalBean.ofStr(gatewayId);
        OptionalBean.ofStr(channel);
        final LambdaQueryWrapper<BizGatewayChannel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizGatewayChannel::getGatewayId, gatewayId);
        queryWrapper.eq(BizGatewayChannel::getChannel, channel);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void toAdd(BizGatewayChannelParam bizGatewayChannelParam) {
        Integer count = this.countByDIdAndChannel(bizGatewayChannelParam);
        if (count == 0) {
            bizGatewayChannelParam.setCreatedAt(DateUtil.date());
            this.add(bizGatewayChannelParam);
            final BizChannelType channelType = bizChannelTypeService.getById(bizGatewayChannelParam.getChannelType());
            if (channelType.getCode().equals(GatewayTypeCodeConstant.FIBRE_OPTICAL_SENSORS_CODE)) {
                BizFosInfoParam bizFosInfoParam = new BizFosInfoParam();
                bizFosInfoParam.setChannelId(bizGatewayChannelParam.getId());
                if(!NumberUtil.isNumber(bizGatewayChannelParam.getStartPoint()) || !NumberUtil.isNumber(bizGatewayChannelParam.getEndPoint()) ){
                    throw new ServiceException("开始点位为非数字类型或结束点位为非数字类型");
                }
                if(ObjectUtil.compare(bizGatewayChannelParam.getStartPoint(),"200") < 0){
                    throw new ServiceException("侦听点位必须大于等于200");
                }
                bizFosInfoParam.setStartPoint(bizGatewayChannelParam.getStartPoint());

                BizGatewayChannelParam channelParam = new BizGatewayChannelParam();
                channelParam.setGatewayId(bizGatewayChannelParam.getGatewayId());
                List<BizGatewayChannelResult> channelResultList = this.listChannel(channelParam);
                Optional<BizGatewayChannelResult> bizGatewayChannelResult = channelResultList.stream().filter(channelResult -> {
                            int startPointCount = bizFosInfoService.count(new LambdaQueryWrapper<BizFosInfo>().le(BizFosInfo::getStartPoint,bizGatewayChannelParam.getStartPoint()));
                            return startPointCount > 0 ;
                        }
                ).findFirst();

                if (!bizGatewayChannelResult.isPresent()) {
                    bizFosInfoService.add(bizFosInfoParam);
                } else {
                    throw new ServiceException("该已存在通道在改点位范围内");
                }
            }
        } else {
            throw new ServiceException("该通道已存在");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void toEdit(BizGatewayChannelParam bizGatewayChannelParam) {
          final boolean update = this.edit(bizGatewayChannelParam);

        if (update) {
            final BizChannelType channelType = bizChannelTypeService.getById(bizGatewayChannelParam.getChannelType());
            if (channelType.getCode().equals(GatewayTypeCodeConstant.FIBRE_OPTICAL_SENSORS_CODE)) {
                LambdaQueryWrapper<BizFosInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(BizFosInfo::getChannelId, bizGatewayChannelParam.getId());
                BizFosInfo fosInfo = bizFosInfoService.getOne(queryWrapper);
                BizFosInfo bizFosInfo = new BizFosInfo();
                if (ObjectUtil.isNotNull(fosInfo)) {
                    bizFosInfo.setId(fosInfo.getId());
                }
                bizFosInfo.setChannelId(bizGatewayChannelParam.getId());
                bizFosInfo.setStartPoint(bizGatewayChannelParam.getStartPoint());
                bizFosInfo.setEndPoint(bizGatewayChannelParam.getEndPoint());
                boolean saveOrUpdate = bizFosInfoService.saveOrUpdate(bizFosInfo);
                //下发更新侦听点任务
                if (saveOrUpdate) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("opticalListeningLocation", bizGatewayChannelParam.getStartPoint());
                    map.put("channel", bizGatewayChannelParam.getChannel());
                    List<Integer> gatewayIds = new ArrayList<>();
                    gatewayIds.add(bizGatewayChannelParam.getGatewayId());
                    taskService.add(GatewayTaskTypeConstant.SYNC_OPTICAL_LISTENING_LOCATION, gatewayIds, JSONUtil.toJsonStr(map));
                }
            }
        }
    }
}
